home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Cream of the Crop 1
/
Cream of the Crop 1.iso
/
PROGRAM
/
ULARN.ARJ
/
ULARN.TAR
/
ularn
/
movem.c
< prev
next >
Wrap
C/C++ Source or Header
|
1989-10-25
|
11KB
|
470 lines
/*
* movem.c (move monster) Larn is copyrighted 1986 by Noah Morgan.
*
* Here are the functions in this file:
*
* movemonst() Routine to move the monsters toward the player
* Function to move a monster at (x,y) -- must determine where
* movemt(x,y)
* Function to actually perform the monster movement
* mmove(x,y,xd,yd)
* Function to look for and move spheres of annihilation
* movsphere()
*/
#include "header.h"
/*
* movemonst() Routine to move the monsters toward the player
*
* This routine has the responsibility to determine which monsters are to
* move, and call movemt() to do the move.
* Returns no value.
*/
static short w1[9],w1x[9],w1y[9];
static int tmp1,tmp2,tmp3,tmp4,distance;
movemonst()
{
register int i,j;
if (c[TIMESTOP]) return; /* no action if time is stopped */
if (c[HASTESELF]) if ((c[HASTESELF]&1)==0) return;
if (spheres) movsphere(); /* move the spheres of annihilation if any */
if (c[HOLDMONST]) return; /* no action if monsters are held */
if (c[AGGRAVATE]) /* determine window of monsters to move */
{
tmp1=playery-5;
tmp2=playery+6;
tmp3=playerx-10;
tmp4=playerx+11;
distance=40; /* depth of intelligent monster movement */
}
else
{
tmp1=playery-3;
tmp2=playery+4;
tmp3=playerx-5;
tmp4=playerx+6;
distance=17; /* depth of intelligent monster movement */
}
if (level == 0) /* if on outside level monsters can move in perimeter */
{
if (tmp1 < 0) tmp1=0;
if (tmp2 > MAXY) tmp2=MAXY;
if (tmp3 < 0) tmp3=0;
if (tmp4 > MAXX) tmp4=MAXX;
}
else /* if in a dungeon monsters can't be on the perimeter (wall there) */
{
if (tmp1 < 1) tmp1=1;
if (tmp2 > MAXY-1) tmp2=MAXY-1;
if (tmp3 < 1) tmp3=1;
if (tmp4 > MAXX-1) tmp4=MAXX-1;
}
for (j=tmp1; j<tmp2; j++) /* now reset monster moved flags */
for (i=tmp3; i<tmp4; i++)
moved[i][j] = 0;
moved[lasthx][lasthy]=0;
if (c[AGGRAVATE] || !c[STEALTH]) /* who gets moved? split for efficiency */
{
for (j=tmp1; j<tmp2; j++) /* look thru all locations in window */
for (i=tmp3; i<tmp4; i++)
if (mitem[i][j]) /* if there is a monster to move */
if (moved[i][j]==0) /* if it has not already been moved */
movemt(i,j); /* go and move the monster */
}
else /* not aggravated and not stealth */
{
for (j=tmp1; j<tmp2; j++) /* look thru all locations in window */
for (i=tmp3; i<tmp4; i++)
if (mitem[i][j]) /* if there is a monster to move */
if (moved[i][j]==0) /* if it has not already been moved */
if (stealth[i][j]) /* if it is asleep due to stealth */
movemt(i,j); /* go and move the monster */
}
if (mitem[lasthx][lasthy]) /* now move monster last hit by player if not already moved */
{
if (moved[lasthx][lasthy]==0) /* if it has not already been moved */
{
movemt(lasthx,lasthy);
lasthx = w1x[0];
lasthy = w1y[0];
}
}
}
/*
* Function to move a monster at (x,y) -- must determine where
* movemt(x,y)
* int x,y;
*
* This routine is responsible for determining where one monster at (x,y)
* will move to. Enter with the monsters coordinates in (x,y).
* Returns no value.
*/
static int tmpitem,xl,xh,yl,yh;
movemt(i,j)
int i,j;
{
register int k,m,z,tmp,xtmp,ytmp,monst;
switch(monst=mitem[i][j]) /* for half speed monsters */
{
case TROGLODYTE:
case HOBGOBLIN:
case METAMORPH:
case XVART:
case INVISIBLESTALKER:
case ICELIZARD:
if ((gtime & 1) == 1) return;
};
/* choose destination randomly if scared */
tmp=0;
{
register int i, j;
for (i=0; i<26; i++)
if (iven[i]==OHANDofFEAR){
tmp=1;
break;
}
}
if (c[SCAREMONST]){
if (tmp==1) tmp=2;
}
else if ((tmp==1) && (rnd(10) > 4)) tmp=0;
if ((monst > DEMONLORD)||(monst == PLATINUMDRAGON)) {
tmp = (tmp==1) ? 0 : (rnd(10) > 5);
}
if (tmp) {
if ((xl = i+rnd(3)-2) < 0) xl=0;
if (xl >= MAXX) xl=MAXX-1;
if ((yl = j+rnd(3)-2) < 0) yl=0;
if (yl >= MAXY) yl=MAXY-1;
if ((tmp=item[xl][yl]) != OWALL)
if (mitem[xl][yl] == 0)
if ((mitem[i][j] != VAMPIRE) || (tmpitem != OMIRROR))
if (tmp != OCLOSEDDOOR)
mmove(i,j,xl,yl);
return;
}
if (monster[monst].intelligence > 10-c[HARDGAME]) /* if smart monster */
/* intelligent movement here -- first setup screen array */
{
xl=tmp3-2;
yl=tmp1-2;
xh=tmp4+2;
yh=tmp2+2;
vxy(&xl,&yl);
vxy(&xh,&yh);
for (k=yl; k<yh; k++)
for (m=xl; m<xh; m++)
{
if (monst>=DEMONPRINCE)
screen[m][k]=0;
else
switch(item[m][k])
{
case OWALL:
case OELEVATORUP:
case OELEVATORDOWN:
case OPIT:
case OTRAPARROW:
case ODARTRAP:
case OCLOSEDDOOR:
case OTRAPDOOR:
case OTELEPORTER:
smm:
screen[m][k]=127;
break;
case OMIRROR:
if (mitem[m][k]==VAMPIRE) goto smm;
default:
screen[m][k]=0;
break;
};
}
screen[playerx][playery]=1;
/* now perform proximity ripple from playerx,playery to monster */
xl=tmp3-1;
yl=tmp1-1;
xh=tmp4+1;
yh=tmp2+1;
vxy(&xl,&yl);
vxy(&xh,&yh);
for (tmp=1; tmp<distance; tmp++) /* only up to 20 squares away */
for (k=yl; k<yh; k++)
for (m=xl; m<xh; m++)
if (screen[m][k]==tmp) /* if find proximity n advance it */
for (z=1; z<9; z++) /* go around in a circle */
{
if (screen[xtmp=m+diroffx[z]][ytmp=k+diroffy[z]]==0)
screen[xtmp][ytmp]=tmp+1;
if (xtmp==i && ytmp==j) goto out;
}
out:
if (tmp<distance) /* did find connectivity */
/* now select lowest value around playerx,playery */
for (z=1; z<9; z++) /* go around in a circle */
if (screen[xl=i+diroffx[z]][yl=j+diroffy[z]]==tmp)
if (!mitem[xl][yl]) {
mmove(i,j,w1x[0]=xl,w1y[0]=yl);
return;
}
}
/* dumb monsters move here */
xl=i-1;
yl=j-1;
xh=i+2;
yh=j+2;
if (i<playerx) xl++;
else if (i>playerx) --xh;
if (j<playery) yl++;
else if (j>playery) --yh;
for (k=0; k<9; k++) w1[k] = 10000;
for (k=xl; k<xh; k++)
for (m=yl; m<yh; m++) /* for each square compute distance to player */
{
tmp = k-i+4+3*(m-j);
tmpitem = item[k][m];
if (tmpitem!=OWALL || (k==playerx && m==playery))
if (mitem[k][m]==0)
if ((mitem[i][j] != VAMPIRE) || (tmpitem != OMIRROR))
if (tmpitem!=OCLOSEDDOOR)
{
w1[tmp] = (playerx-k)*(playerx-k)+(playery-m)*(playery-m);
w1x[tmp] = k;
w1y[tmp] = m;
}
}
tmp = 0;
for (k=1; k<9; k++) if (w1[tmp] > w1[k]) tmp=k;
if (w1[tmp] < 10000)
if ((i!=w1x[tmp]) || (j!=w1y[tmp]))
mmove(i,j,w1x[tmp],w1y[tmp]);
}
/*
* Function to actually perform the monster movement
* mmove(x,y,xd,yd)
* int x,y,xd,yd;
*
* Enter with the from coordinates in (x,y) and the destination coordinates
* in (xd,yd).
*/
mmove(aa,bb,cc,dd)
int aa,bb,cc,dd;
{
register int tmp,i,x,flag;
char *who,*p;
flag=0; /* set to 1 if monster hit by arrow trap */
if ((cc==playerx) && (dd==playery)) {
hitplayer(aa,bb);
moved[aa][bb] = 1;
return;
}
i=item[cc][dd];
if ((i==OPIT) || (i==OTRAPDOOR))
switch(mitem[aa][bb]) {
case SPIRITNAGA:
case PLATINUMDRAGON:
case WRAITH:
case VAMPIRE:
case SILVERDRAGON:
case POLTERGEIST:
case DEMONLORD:
case DEMONLORD+1:
case DEMONLORD+2:
case DEMONLORD+3:
case DEMONLORD+4:
case DEMONLORD+5:
case DEMONLORD+6:
case DEMONPRINCE:
case LUCIFER:
break;
default:
mitem[aa][bb]=0; /* fell in a pit or trapdoor */
};
tmp = mitem[cc][dd] = mitem[aa][bb];
if (i==OANNIHILATION)
if (tmp>=DEMONLORD) /* demons dispel spheres */
{
flag=0;
for (x=0;x<26;x++)
if(iven[x]==OSPHTALISMAN) flag++;
if (flag==0
|| (flag && tmp == LUCIFER && (rnd(10) > 7))) {
cursors();
lprintf("\nThe %s dispels the sphere!",
monster[tmp].name);
rmsphere(cc,dd); /* delete the sphere */
}
else i=tmp=mitem[cc][dd]=0;
}
else i=tmp=mitem[cc][dd]=0;
stealth[cc][dd]=1;
flag=0;
if ((hitp[cc][dd] = hitp[aa][bb]) < 0) hitp[cc][dd]=1;
if (tmp==LEMMING) {
if (rnd(100)<=9) {
mitem[aa][bb] = LEMMING;
know[aa][bb]=1;
}
else mitem[aa][bb] = 0;
}
else mitem[aa][bb] = 0;
moved[cc][dd] = 1;
if (tmp == LEPRECHAUN)/* leprechaun takes gold */
switch(i) {
case OGOLDPILE:
case OMAXGOLD:
case OKGOLD:
case ODGOLD:
case ODIAMOND:
case ORUBY:
case OEMERALD:
case OSAPPHIRE:
item[cc][dd] = 0;
};
if (tmp == TROLL) /* if a troll regenerate him */
if ((gtime & 1) == 0)
if (monster[tmp].hitpoints > hitp[cc][dd]) hitp[cc][dd]++;
if (i==OTRAPARROW) /* arrow hits monster */
{
who = "An arrow";
if ((hitp[cc][dd] -= rnd(10)+level) <= 0) {
mitem[cc][dd]=0;
flag=2;
}
else flag=1;
}
if (i==ODARTRAP) /* dart hits monster */
{
who = "A dart";
if ((hitp[cc][dd] -= rnd(6)) <= 0) {
mitem[cc][dd]=0;
flag=2;
}
else flag=1;
}
if (tmp < DEMONLORD)
if (i==OTELEPORTER) /* monster hits teleport trap */
{
flag=3;
fillmonst(mitem[cc][dd]);
mitem[cc][dd]=0;
}
if (tmp < DEMONLORD)
if ((i==OELEVATORUP) || (i==OELEVATORDOWN)) {
mitem[cc][dd]=0;
flag=4;
}
if (c[BLINDCOUNT]) return;
/* if blind don't show where monsters are */
if (know[cc][dd] & 1) {
p=0;
if (flag) cursors();
switch(flag) {
case 1:
p="\n%s hits the %s";
break;
case 2:
p="\n%s hits and kills the %s";
break;
case 3:
p="\nThe %s%s gets teleported";
who="";
break;
case 4:
p="\nThe %s%s is carried away by an elevator!";
who="";
break;
};
if (p) {
lprintf(p,who,monster[tmp].name);
beep();
}
}
if (know[aa][bb] & 1) show1cell(aa,bb);
if (know[cc][dd] & 1) show1cell(cc,dd);
}
/*
* movsphere() Function to look for and move spheres of annihilation
*
* This function works on the sphere linked list, first duplicating the list
* (the act of moving changes the list), then processing each sphere in order
* to move it. They eat anything in their way, including stairs, volcanic
* shafts, potions, etc, except for upper level demons, who can dispel
* spheres.
* No value is returned.
*/
#define SPHMAX 20 /* maximum number of spheres movsphere can handle */
movsphere()
{
register int x,y,dir,len;
register struct sphere *sp,*sp2;
struct sphere sph[SPHMAX];
/* first duplicate sphere list */
/* look through sphere list */
for (sp=0,x=0,sp2=spheres; sp2; sp2=sp2->p)
/* only if this level */
if (sp2->lev == level) {
sph[x] = *sp2;
sph[x++].p = 0; /* copy the struct */
if (x>1)
sph[x-2].p = &sph[x-1]; /* link pointers */
}
if (x) sp= sph; /* if any spheres, point to them */
else return; /* no spheres */
/* look through sphere list */
for (sp=sph; sp; sp=sp->p) {
x = sp->x;
y = sp->y;
if (item[x][y]!=OANNIHILATION) continue;/* not really there */
/* has sphere run out of gas? */
if (--(sp->lifetime) < 0) {
rmsphere(x,y); /* delete sphere */
continue;
}
/* time to move the sphere */
switch(rnd((int)max(7,c[INTELLIGENCE]>>1))) {
case 1:
case 2: /* change direction to a random one */
sp->dir = rnd(8);
default: /* move in normal direction */
dir = sp->dir;
len = sp->lifetime;
rmsphere(x,y);
newsphere(x+diroffx[dir],y+diroffy[dir],dir,len);
};
}
}